package com.guigui.gulimall.ware.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.guigui.common.exception.NoStockException;
import com.guigui.common.to.OrderTo;
import com.guigui.common.to.SkuInfoTo;
import com.guigui.common.to.StockLockedTo;
import com.guigui.common.to.ware.WareStockVo;
import com.guigui.common.utils.PageUtils;
import com.guigui.common.utils.Query;
import com.guigui.gulimall.ware.dao.WareSkuDao;
import com.guigui.gulimall.ware.dto.OrderLockDto;
import com.guigui.gulimall.ware.dto.ProductLockDto;
import com.guigui.gulimall.ware.entity.PurchaseDetailEntity;
import com.guigui.gulimall.ware.entity.WareOrderTaskDetailEntity;
import com.guigui.gulimall.ware.entity.WareOrderTaskEntity;
import com.guigui.gulimall.ware.entity.WareSkuEntity;
import com.guigui.gulimall.ware.feign.OrderFeignService;
import com.guigui.gulimall.ware.feign.ProductSpuInfoFeignService;
import com.guigui.gulimall.ware.service.WareOrderTaskDetailService;
import com.guigui.gulimall.ware.service.WareOrderTaskService;
import com.guigui.gulimall.ware.service.WareSkuService;
import com.mysql.cj.util.StringUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;


@Service("wareSkuService")
public class WareSkuServiceImpl extends ServiceImpl<WareSkuDao, WareSkuEntity> implements WareSkuService {

    @Autowired
    private ProductSpuInfoFeignService productSpuInfoFeignService;

    @Autowired
    private WareOrderTaskService wareOrderTaskService;

    @Autowired
    private WareOrderTaskDetailService wareOrderTaskDetailService;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private OrderFeignService orderFeignService;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        QueryWrapper<WareSkuEntity> queryWrapper = new QueryWrapper<>();

        String skuId = (String) params.get("skuId");
        if (!StringUtils.isNullOrEmpty(skuId)) queryWrapper.eq("sku_id",Long.valueOf(skuId));

        String wareId = (String) params.get("wareId");
        if (!StringUtils.isNullOrEmpty(wareId)) queryWrapper.eq("ware_id",Long.valueOf(wareId));


        IPage<WareSkuEntity> page = this.page(
                new Query<WareSkuEntity>().getPage(params),
                queryWrapper
        );

        return new PageUtils(page);
    }

    @Override
    public void addWare(List<PurchaseDetailEntity> detailIds) {
        detailIds.forEach(detailId -> {
            WareSkuEntity wareSkuEntity = this.baseMapper.selectOne(
                    new QueryWrapper<WareSkuEntity>().eq("sku_id", detailId.getSkuId()).eq("ware_id", detailId.getWareId())
            );
            if (wareSkuEntity != null) {
                this.baseMapper.addWare(detailId.getSkuId(), detailId.getWareId(), detailId.getSkuNum());
            } else {
                WareSkuEntity skuEntity = new WareSkuEntity();

                skuEntity.setSkuId(detailId.getSkuId());
                skuEntity.setStock(detailId.getSkuNum());
                try {
                    SkuInfoTo skuInfoBySkuId = productSpuInfoFeignService.getSkuInfoBySkuId(detailId.getSkuId());
                    if (skuInfoBySkuId != null) {
                        skuEntity.setSkuName(skuInfoBySkuId.getSkuName());
                    }
                } catch (Exception e) {
                    log.error("getSkuInfoBySkuId查询失败");
                }
                skuEntity.setWareId(detailId.getWareId());
                skuEntity.setStockLocked(0);
                this.baseMapper.insert(skuEntity);
            }
        });

    }

    @Override
    public List<WareStockVo> getStock(List<Long> skuIds) {
        return skuIds.stream().map(skuId -> {
            WareStockVo vo = new WareStockVo();
            Long stockCount = this.baseMapper.getStock(skuId);
            vo.setSkuId(skuId);
            vo.setStock(stockCount != null && stockCount > 0);
            return vo;
        }).collect(Collectors.toList());
    }

    @Transactional(rollbackFor = Throwable.class)
    @Override
    public List<WareStockVo> lockProduct(OrderLockDto orderLockDto) {

        List<ProductLockDto> productsLock = orderLockDto.getProductsLock();

        List<WareStockVo> wareStockVos = new ArrayList<>(productsLock.size());

        WareOrderTaskEntity wareOrderTask = new WareOrderTaskEntity();
        wareOrderTask.setOrderSn(orderLockDto.getOrderSn());
        wareOrderTask.setCreateTime(new Date());
        wareOrderTaskService.save(wareOrderTask);

        // 查库存
        for (ProductLockDto prod : productsLock) {
            List<Long> wareIds = this.baseMapper.queryWhereStockBySkuId(prod.getSkuId(), prod.getCount());
            if (wareIds.size() > 0) {
                WareStockVo wareStockVo = new WareStockVo();

                for (Long wareId : wareIds) {
                    Integer row = this.baseMapper.lockProduct(prod.getSkuId(), prod.getCount(), wareId);
                    wareStockVo = new WareStockVo();
                    wareStockVo.setSkuId(prod.getSkuId());
                    if (row != 0) {
                        // 锁库存成功
                        /*
                        库存锁定成功
                        1、 创建订单任务
                        2、 创建订单任务详情
                            1. 任务对象发送给mq
                         */
                        // 任务详情保存到数据库
                        WareOrderTaskDetailEntity wareOrderTaskDetail = new WareOrderTaskDetailEntity(null, prod.getSkuId(), prod.getTitle(), prod.getCount(), wareOrderTask.getId(), wareId, 1);
                        wareOrderTaskDetailService.save(wareOrderTaskDetail);

                        // 发送mq消息,库存锁定消息
                        sendStockLockedMsg(wareOrderTaskDetail.getId());
                        wareStockVo.setStock(true);
                        break;
                    }
                }

                if (!wareStockVo.getStock()) {
                    // 商品锁定失败，这里抛异常，以上全部回滚
                    throw new NoStockException();
                }

            } else {
                // 没有仓库有该商品的库存
                throw new NoStockException();
            }
        }

        return wareStockVos;
    }

    /**
     * 解锁库存
     */
    @Transactional(rollbackFor = Throwable.class)
    @Override
    public void unLockStock(StockLockedTo stockLockedTo) {
        System.out.println("库存超时准备解锁库存。。。。");
        Long orderTaskDetailId = stockLockedTo.getOrderTaskDetailId();
        WareOrderTaskDetailEntity byId = wareOrderTaskDetailService.getById(orderTaskDetailId);
        if (byId != null) {
            // 订单任务
            WareOrderTaskEntity orderTask = wareOrderTaskService.getById(byId.getTaskId());
            if (orderTask != null) {
            /*
            这里不做从新入队操作，默认不确认消息就是重新入队。
             查到数据
                1. 询问order服务，是否需要解锁库存
                    0. 查不到订单，可能由于数据回滚，订单并没有创建出来-----解锁库存
                    1. 查到订单
                        订单已付款状态---不解锁库存
                        订单已取消状态---解锁库存
                        订单其他状态---。。。
             */
                OrderTo orderEntityByOrderSn = orderFeignService.getOrderEntityByOrderSn(orderTask.getOrderSn());
                Set<Integer> statusSet = new HashSet<>(); // 这些状态解锁库存
                statusSet.add(4);
                statusSet.add(5);
                if (orderEntityByOrderSn == null ||  (byId.getLockStatus() == 1 && statusSet.contains(orderEntityByOrderSn.getStatus())) ) {
                    // 订单创建成功，但已经关闭。解锁库存，确认消息
                    this.baseMapper.unLockStock(byId.getWareId(), byId.getSkuId(), byId.getSkuNum());

                    WareOrderTaskDetailEntity detail = new WareOrderTaskDetailEntity();
                    detail.setLockStatus(2);
                    detail.setId(byId.getId());
                    wareOrderTaskDetailService.updateById(detail);
                }

                // 无论是否有这个订单，都应该确认消息
//                channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
            }
        } else {
            // 没查到数据，说明发生了回滚，这里确认消息即可。
//            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        }

    }

    @Transactional(rollbackFor = Throwable.class)
    @Override
    public void unLockStock(OrderTo order) {
        // 订单已经取消。解锁库存，确认消息
        System.out.println("订单超时准备解锁库存。。。。");
        WareOrderTaskEntity orderTask = wareOrderTaskService.getOne(new QueryWrapper<WareOrderTaskEntity>().eq("order_sn", order.getOrderSn()));
        if (orderTask != null) {
            List<WareOrderTaskDetailEntity> detailEntities = wareOrderTaskDetailService.list(
                    new QueryWrapper<WareOrderTaskDetailEntity>().eq("task_id", orderTask.getId()).eq("lock_status", 1));

            for (WareOrderTaskDetailEntity detail : detailEntities) {
                this.baseMapper.unLockStock(detail.getWareId(), detail.getSkuId(), detail.getSkuNum());
            }

            // 订单任务详情更新状态
            if (detailEntities.size() > 0) {
                List<WareOrderTaskDetailEntity> collect = detailEntities.stream().map(e -> {
                    WareOrderTaskDetailEntity detail = new WareOrderTaskDetailEntity();
                    detail.setId(e.getId());
                    detail.setLockStatus(2);
                    return detail;
                }).collect(Collectors.toList());
                wareOrderTaskDetailService.updateBatchById(collect);
            }
        }
    }


    /**
     * 发送库存解锁消息
     */
    private void sendStockLockedMsg(Long OrderTaskDetailId) {
        StockLockedTo stockLockedTo = new StockLockedTo();
        stockLockedTo.setOrderTaskDetailId(OrderTaskDetailId);
        rabbitTemplate.convertAndSend("stock-event-exchange", "stock.lock", stockLockedTo);
    }



}